﻿#region 文件信息

/*----------------------------------------------------------------
//
// 文件名称：
// 文件功能描述：
// 设计要求：
//
// 文 件 名：    VampirewalCoreEventBus
// 创建者：      杨程
// 创建日期：	    2022/12/31 15:36:23

//----------------------------------------------------------------*/

#endregion

using System.Reflection;

namespace Vampirewal.Core.EventBus;

/// <summary>
/// VampirewalCore简单事件总线管理器
/// </summary>
public sealed class VampirewalCoreEventBusManager
{
    private static VampirewalCoreEventBusManager _instance;
    private static object _objLock = new object();

    /// <summary>
    /// 获取单例实例
    /// </summary>
    /// <returns></returns>
    public static VampirewalCoreEventBusManager GetInstance()
    {
        if (_instance == null)
        {
            lock (_objLock)
            {
                if (_instance == null)
                {
                    _instance = new VampirewalCoreEventBusManager();
                }
            }
        }
        return _instance;
    }

    /// <summary>
    ///
    /// </summary>
    public VampirewalCoreEventBusManager()
    {
        //构造函数
        Subscribers = new List<Subscriber>();
    }

    private List<Subscriber> Subscribers { get; set; }

    #region [     注册     ]

    /// <summary>
    /// 全部注册
    /// </summary>
    public void RegisterAll()
    {
        Type[]? types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()).Where(t => t.GetInterfaces().Contains(typeof(IVampirewalCoreEventFactory))).ToArray();

        foreach (Type type in types)
        {
            if (type != null)
            {
                object? obj = Activator.CreateInstance(type);

                if (obj != null)
                {
                    IEnumerable<MethodInfo>? methods = type.GetMethods();

                    foreach (MethodInfo method in methods)
                    {
                        SubscribeEventAttribute? attr = method.GetCustomAttribute<SubscribeEventAttribute>();

                        if (attr != null)
                        {
                            if (string.IsNullOrEmpty(attr.Token))
                            {
                                throw new VampirewalCoreEventBusException("Token不能为null！");
                            }

                            Subscriber sub = new Subscriber()
                            {
                                Register = obj,
                                Token = $"{attr.Token}",
                                Method = method,
                            };

                            Subscribers.Add(sub);
                        }
                    }
                }
            }
        }
    }

    #endregion

    #region [     推送     ]

    /// <summary>
    /// 推送事件消息
    /// </summary>
    /// <param name="SubscribeToken">订阅的Token</param>
    /// <param name="Params"></param>
    public void Publish(string SubscribeToken, object? Params = null)
    {
        List<Subscriber>? subs = Subscribers.FindAll(f => f.Token == $"{SubscribeToken}");

        Parallel.ForEach(subs, (sub) =>
        {
            EventContext context = new EventContext()
            {
                PassData = Params,
                ExcutingTime = DateTime.Now,
                MethodName = sub.Method.Name,
            };

            var attrs = sub.Method.GetCustomAttributes().Where(w => w is EventBusAOPAttribute).ToList();

            try
            {
                foreach (EventBusAOPAttribute item in attrs)
                {
                    item.ExcuteBefore(context);
                }

                sub.Method.Invoke(sub.Register, new object[] { context });
            }
            catch (Exception ex)
            {
                context.ExceptionInfo = ex.InnerException;
            }
            finally
            {
                context.ExcutedTime = DateTime.Now;

                foreach (EventBusAOPAttribute item in attrs)
                {
                    item.ExcuteAfter(context);
                }
            }
        });
    }

    /// <summary>
    /// 内部方法-订阅
    /// </summary>
    internal void Subscribe(Subscriber sub)
    {
        Subscribers.Add(sub);
    }

    #endregion
}

/// <summary>
/// 订阅者
/// </summary>
internal class Subscriber
{
    /// <summary>
    /// 注册体
    /// </summary>
    public object? Register { get; set; }

    /// <summary>
    /// 口令
    /// </summary>
    public string? Token { get; set; }

    /// <summary>
    /// 方法
    /// </summary>
    public MethodInfo? Method { get; set; }
}

/// <summary>
/// 事件上下文
/// </summary>
public class EventContext
{
    /// <summary>
    /// 传递过来的参数
    /// </summary>
    public object? PassData { get; set; }

    /// <summary>
    /// 执行的方法名
    /// </summary>
    public string MethodName { get; internal set; } = "";

    /// <summary>
    /// 开始执行时间
    /// </summary>
    public DateTime? ExcutingTime { get; internal set; }

    /// <summary>
    /// 执行结束时间
    /// </summary>
    public DateTime? ExcutedTime { get; internal set; }

    /// <summary>
    /// 异常信息
    /// </summary>
    public Exception? ExceptionInfo { get; internal set; }
}

/// <summary>
/// VampirewalCore事件总线异常类
/// </summary>
internal class VampirewalCoreEventBusException : Exception
{
    /// <summary>
    /// VampirewalCore事件总线异常类
    /// </summary>
    /// <param name="ErrorMsg">异常信息</param>
    public VampirewalCoreEventBusException(string ErrorMsg) : base(ErrorMsg)
    {
    }
}